define(async () => {
    const util = await require("../util");
    const Node = await require("Node");
    
    /**
     * 雪碧图选项类
     * 
     * 为节点提供动态化的雪碧图参数
     */
     class SpriteOptions {

        node;  //节点实例
        clipWidth;  //截取宽度
        clipHeight;  //截取高度
        offsetX;  //X轴偏移
        offsetY;  //Y轴偏移
        blockWidth;  //图块宽度
        blockHeight;  //图块高度
        bleedWidth;  //出血线宽度
        frameDuration;  //每帧持续时长
        loop;  //是否循环播放
        _status = {
            blockXIndex: 0,  //雪碧图图块X轴图块位置
            blockYIndex: 0,  //雪碧图图块Y轴图块位置
            playedFrames: 0  //雪碧图已播放画面数
        };

        constructor(node, options = {}) {
            util.assert(Node.isInstance(node), "node must be an Node instance");
            util.assert(util.isObject(options), "options must be an Object");
            const { offsetX, offsetY, clipWidth, clipHeight, blockWidth, blockHeight, bleedWidth, frameDuration, loop } = options;
            util.assert(util.isUndefined(offsetX) || util.isNumber(offsetX), "offsetX must be an Object");
            util.assert(util.isUndefined(offsetY) || util.isNumber(offsetY), "offsetY must be an Object");
            util.assert(util.isNumber(blockWidth), "blockWidth must be an Number");
            util.assert(util.isNumber(blockHeight), "blockHeight must be an Number");
            util.assert(util.isUndefined(frameDuration) || util.isNumber(frameDuration), "frameDuration must be an Number");
            util.assert(util.isUndefined(clipWidth) || (clipWidth >= blockWidth && clipWidth % blockWidth === 0), "clipWidth does not match blockWidth");
            util.assert(util.isUndefined(clipHeight) || (clipHeight >= blockHeight && clipHeight % blockHeight === 0), "clipHeight does not match blockHeight");
            this.node = node;
            this.offsetX = util.defaultTo(offsetX, 0);
            this.offsetY = util.defaultTo(offsetY, 0);
            this.clipWidth = util.defaultTo(clipWidth, 0);
            this.clipHeight = util.defaultTo(clipHeight, 0);
            this.blockWidth = blockWidth;
            this.blockHeight = blockHeight;
            this.bleedWidth = util.defaultTo(bleedWidth, 0);
            this.frameDuration = util.defaultTo(frameDuration, 0) / 1000;
            this.loop = util.defaultTo(loop, true);
        }

        /**
         * 获取雪碧图下一图块裁剪参数
         * 
         * @return {Object} clipX 裁剪起始X轴坐标
         *                  clipY 裁剪起始Y轴坐标
         *                  clipWidth 裁剪宽度
         *                  clipHeight 裁剪高度
         */
        getNextClipParams() {
            const clipX = this.offsetX + this._status.blockXIndex * this.blockWidth + (this._status.blockXIndex > 0 ? this.bleedWidth : 0);
            const clipY = this.offsetY + this._status.blockYIndex * this.blockHeight + (this._status.blockYIndex > 0 ? this.bleedWidth : 0);
            const clipWidth = this.blockWidth;
            const clipHeight = this.blockHeight;
            //播放一定帧数后才切换下一图块
            if(this.frameDuration !== 0 && this._status.playedFrames >= this.frameDuration * this.node.fps) {
                this._status.playedFrames = 0;
                //如果X轴图块个数大于Y轴图块个数则按X轴方向播放否则是Y轴方向播放，只能二选一
                if(this.blockXCount > this.blockYCount)
                    this._status.blockXIndex = this._status.blockXIndex >= this.blockXCount - 1 ? (this.loop ? 0 : this._status.blockXIndex) : this._status.blockXIndex + 1;
                else
                    this._status.blockYIndex = this._status.blockYIndex >= this.blockYCount - 1 ? (this.loop ? 0 : this._status.blockYIndex) : this._status.blockYIndex + 1;
            }
            this._status.playedFrames++;
            return { clipX, clipY, clipWidth, clipHeight };
        }

        /**
         * 获得当前参数下的X轴图块个数
         */
        get blockXCount() {
            if(this.clipWidth + this.offsetX > this.node.image.wdith)
                return (this.clipWidth - this.offsetX) / this.blockWidth;
            return this.clipWidth / this.blockWidth;
        }

        /**
         * 获得当前参数下的Y轴图块个数
         */
        get blockYCount() {
            if(this.clipHeight + this.offsetY > this.node.image.height)
                return (this.clipHeight - this.offsetY) / this.blockHeight;
            return this.clipHeight / this.blockHeight;
        }

        // /**
        //  * 设置动画速度
        //  */
        // set animationSpeed(value) {
        //     this.frameDuration = value > 0 ? 10 - (value - 1) * 10 : 0;
        // }

        // /**
        //  * 获取动画速度
        //  */
        // get animationSpeed() {
        //     return this.frameDuration / 10;
        // }

    }

    class _Image extends Node {

        url;  //远程URL或base64
        sprite;  //雪碧图选项
        _image;  //Image对象
        _autoWidth = false;  //是否自动处理宽度
        _autoHeight = false;  //是否自动处理高度

        constructor(options) {
            //如果未设置宽高则为自动宽高状态，宽高将由image对象自动确定
            let autoWidth, autoHeight;
            if(!util.isNumber(options.width)) {
                options.width = 0;
                autoWidth = true;
            }
            if(!util.isNumber(options.height)) {
                options.height = 0;
                autoHeight = true;
            }
            super(options);
            const { url, image, sprite } = options;
            util.assert(util.isString(url) || util.isImage(image), "url must be an String or image must be an Image instance");
            this.url = url;
            this._autoWidth = autoWidth;
            this._autoHeight = autoHeight;
            if(util.isImage(image))
                this.image = image;
            if(sprite)
                this.sprite = new SpriteOptions(this, sprite);  //初始化雪碧图参数
        }

        /**
         * 预处理图像
         * 
         * 一般是下载图像
         */
        async preprocessing() {
            if(this.image)
                return;
            this.image = await new Promise((resolve, reject) => {
                const image = new Image();
                image.src = this.url;
                image.onload = () => resolve(image);
                image.onerror = err => reject(err);
            });
        }

        /**
         * 渲染图像
         */
        render() {
            if(!this.image)
                return logger.warn("image is not preprocessing");
            super.render();  //父节点先处理渲染
            //只有在图层视窗内才渲染
            if(this.inViewport) {
                let clipParams = [];
                //如果使用雪碧图将获得裁剪参数
                if(this.sprite) {
                    const { clipX, clipY, clipWidth, clipHeight } = this.sprite.getNextClipParams();
                    clipParams = [clipX, clipY, clipWidth, clipHeight];
                }
                //如果存在旋转角度则需要针对旋转特殊处理否则直接画图即可
                if(this.rotate !== 0 || this.offsetAngle !== 0) {
                    this.layer.offscreenContext.save();  //暂存当前上下文
                    const widthHalf = this.width * this.scaleX / 2;
                    const heightHalf = this.height * this.scaleY / 2;
                    this.layer.offscreenContext.translate(this.renderX + widthHalf, this.renderY + heightHalf);  //移动原点到图像的中心点
                    this.layer.offscreenContext.rotate((this.rotate + this.offsetAngle) * Math.PI / 180);  //旋转画布
                    this.layer.offscreenContext.drawImage(this.image, ...clipParams, -widthHalf - this.rotateX, -heightHalf - this.rotateY, this.width * this.scaleX, this.height * this.scaleY);  //绘制图像
                    this.layer.offscreenContext.restore();  //恢复暂存的上下文（恢复原点位置和旋转位置）
                }
                else
                    this.layer.offscreenContext.drawImage(this.image, ...clipParams, this.renderX, this.renderY, this.width * this.scaleX, this.height * this.scaleY);  //直接绘制图像
            }
        }

        set image(value) {
            util.assert(util.isImage(value), "image must be an Image instance");
            this._image = value;
            //如果为自动宽度则使用图像宽度
            if(this._autoWidth)
                this.width = this._image.width;
            //如果为自动高度则使用图像高度
            if(this._autoHeight)
                this.height = this._image.height;
            if(this.sprite) {
                //使用雪碧图但未设置裁剪宽度则使用图像宽度
                if(!this.sprite.clipWidth)
                    this.sprite.clipWidth = this._image.width;
                //使用雪碧图但未设置裁剪高度则使用图像高度
                if(!this.sprite.clipHeight)
                    this.sprite.clipHeight = this._image.height;
            }
        }

        get image () {
            return this._image;
        }
        
    }

    return _Image;
});